﻿using System;
using System.Collections.Generic;

namespace g4
{
    /// <summary>
    /// 向网格中插入多边形的操作类
    /// 功能：将2D多边形（带内孔）插入到3D网格中（假设网格坐标为(u,v,0)，即位于XY平面）
    /// 本质是对MeshInsertUVPolyCurve的封装，简化多边形插入流程
    /// 输出包含插入的边界边集合和多边形内部的三角形
    /// </summary>
    public class MeshInsertPolygon
    {
        /// <summary>
        /// 目标网格（需位于XY平面，坐标形式为(u,v,0)）
        /// </summary>
        public DMesh3 Mesh;

        /// <summary>
        /// 要插入的2D多边形（包含外边界和内孔）
        /// </summary>
        public GeneralPolygon2d Polygon;


        /// <summary>
        /// 是否简化插入结果（优化边界边，减少冗余顶点/边）
        /// </summary>
        public bool SimplifyInsertion = true;

        /// <summary>
        /// 外边界插入器（处理多边形外轮廓）
        /// </summary>
        public MeshInsertUVPolyCurve OuterInsert;

        /// <summary>
        /// 内孔插入器列表（处理多边形的所有内孔）
        /// </summary>
        public List<MeshInsertUVPolyCurve> HoleInserts;

        /// <summary>
        /// 插入的多边形边界边集合（外边界+所有内孔的边）
        /// </summary>
        public HashSet<int> InsertedPolygonEdges;

        /// <summary>
        /// 多边形内部的三角形选择集（标记插入区域内的所有三角形）
        /// </summary>
        public MeshFaceSelection InteriorTriangles;

        /// <summary>
        /// 执行多边形插入操作
        /// </summary>
        /// <returns>插入成功返回true，否则返回false</returns>
        public bool Insert()
        {
            // 初始化外边界插入器，处理多边形的外轮廓
            OuterInsert = new MeshInsertUVPolyCurve(Mesh, Polygon.Outer);
            // 验证外边界插入器的合法性（断言失败则抛出异常）
            Util.gDevAssert(OuterInsert.Validate() == ValidationStatus.Ok);
            // 应用外边界插入（在网格中切割出外边界）
            bool outerApplyOK = OuterInsert.Apply();
            // 若外边界插入失败或未生成有效环，则返回失败
            if (outerApplyOK == false || OuterInsert.Loops.Count == 0)
                return false;
            // 若启用简化，则优化外边界（合并共线边等）
            if (SimplifyInsertion)
                OuterInsert.Simplify();

            // 处理所有内孔
            HoleInserts = new List<MeshInsertUVPolyCurve>(Polygon.Holes.Count);
            for (int hi = 0; hi < Polygon.Holes.Count; ++hi)
            {
                // 为每个内孔创建插入器
                MeshInsertUVPolyCurve insert = new MeshInsertUVPolyCurve(Mesh, Polygon.Holes[hi]);
                // 验证内孔插入器的合法性
                Util.gDevAssert(insert.Validate() == ValidationStatus.Ok);
                // 应用内孔插入（在网格中切割出内孔边界）
                insert.Apply();
                // 简化内孔边界
                if (SimplifyInsertion)
                    insert.Simplify();
                // 添加到内孔插入器列表
                HoleInserts.Add(insert);
            }


            // 查找位于多边形内部的种子三角形（用于后续填充）
            int seed_tri = -1;
            // 获取外边界环（假设第一个环为有效外边界）
            EdgeLoop outer_loop = OuterInsert.Loops[0];
            // 遍历外边界的边，寻找内外侧三角形
            for (int i = 0; i < outer_loop.EdgeCount; ++i)
            {
                int eid = outer_loop.Edges[i];
                // 跳过无效边
                if (!Mesh.IsEdge(eid))
                    continue;

                // 获取边关联的两个三角形（A和B）
                Index2i et = Mesh.GetEdgeT(eid);
                // 计算三角形A的重心
                Vector3d ca = Mesh.GetTriCentroid(et.a);
                // 判断重心是否在多边形外边界内（2D判断）
                bool in_a = Polygon.Outer.Contains(ca.xy);
                // 计算三角形B的重心
                Vector3d cb = Mesh.GetTriCentroid(et.b);
                bool in_b = Polygon.Outer.Contains(cb.xy);

                // 找到一个在内部、一个在外部的三角形对，取内部的作为种子
                if (in_a && !in_b)
                {
                    seed_tri = et.a;
                    break;
                }
                else if (in_b && !in_a)
                {
                    seed_tri = et.b;
                    break;
                }
            }
            // 若未找到种子三角形，抛出异常
            if (seed_tri == -1)
                throw new Exception("MeshPolygonsInserter: 无法找到种子三角形！");

            // 收集所有插入的边界边（外边界+内孔）
            InsertedPolygonEdges = new HashSet<int>(outer_loop.Edges);
            foreach (var insertion in HoleInserts)
            {
                // 假设每个内孔插入器的第一个环为有效内孔边界
                foreach (int eid in insertion.Loops[0].Edges)
                    InsertedPolygonEdges.Add(eid);
            }

            // 从种子三角形开始， flood-fill 标记多边形内部的所有三角形
            InteriorTriangles = new MeshFaceSelection(Mesh);
            // 填充规则：仅通过非边界边遍历（遇到InsertedPolygonEdges则停止）
            InteriorTriangles.FloodFill(seed_tri, null, (eid) => {
                return !InsertedPolygonEdges.Contains(eid); // 不是边界边则允许通过
            });

            return true;
        }

    }
}